//
//  IVCSSDK.m
//  ivcs_ios_demo
//
//  Created by zealcomm user on 2020/10/21.
//  Copyright © 2020 zealcomm user. All rights reserved.
//


#import <IVCS/Constant.h>
#import <IVCS/IRTCSDK.h>
#import <IVCS/CCSClient.h>
#import "IvcsCustomer.h"
#import "IvcsCustomerDelegate.h"
#import "API.h"
#import "MyCcsClientMessageDelegate.h"

static NSString *ivcsSDKErrorDomain = @"zealcomm.ivcs";

@interface IvcsCustomer()<IvcsCustomerDelegate , IRTCSDKDelegate>

/// 保存用户的登录信息
@property(strong , nonatomic)ZcoModelUserInfo *zcoModelUserInfo;

/// ccs socketIo client
@property(strong,nonatomic)CCSClient *ccsClient;

/// irtc sdk
@property(strong,nonatomic)IRTCSDK *irtcSDK;

/// default webrtc stream setting parameter
@property(strong,nonatomic)MediaStreamSettingOptions *mediaOptions;

/// zms roomn token
@property(copy,nonatomic)NSString *roomToken;

@property(copy , nonatomic)NSString *baseUrl;

@property(strong , nonatomic)NSMutableDictionary *labelAndStreams;

@property(copy , nonatomic)NSString *localStreamLabel ;

@property(strong, nonatomic) IRTCLocalCameraStream *localStream;
@end

@implementation IvcsCustomer

relizeSingleInstance(Customer)

// 当没有传递要发送的角色时，默认传 agents
NSString* (^ checkRole)(NSString *) = ^(NSString* role){
    return role == nil ? @"agents" : role;
};

-(NSMutableDictionary *)labelAndStreams{
    _labelAndStreams = self.irtcSDK.labelAndStreams;
    return _labelAndStreams;
}

-(void)initWithServiceUrl:(NSString *)serviceUrl name:(NSString *)name password:(NSString *)password org:(NSString *)org mediaOptions:(MediaStreamSettingOptions *)mediaOptions onSuccess:(void (^)(ZcoModelUserInfo * _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
       //数据校验
       if (serviceUrl == nil || name == nil || password == nil || org == nil) {
           NSError *error = [[NSError alloc] initWithDomain:ivcsSDKErrorDomain code:105 userInfo:@{@"reason":@"请检查 url地址 登录名 密码 机构名 是否为空"}];
           onFailure(error);
           return;
       }
       //设置音视频参数，nil则使用默认的音视频参数
       if (mediaOptions == nil) {
           self.mediaOptions = [[MediaStreamSettingOptions alloc] init];
           IRTCStreamConstraints *constraints = [[IRTCStreamConstraints alloc] init];
           constraints.audio = true;
           constraints.video=[[IRTCVideoTrackConstraints alloc] init];
           constraints.video.frameRate = 15;
           constraints.video.resolution = CGSizeMake(640,480);
           constraints.video.devicePosition = AVCaptureDevicePositionFront;
           self.mediaOptions.streamConstraints = constraints;
           IRTCPublishOptions* options=[[IRTCPublishOptions alloc] init];
           IRTCVideoCodecParameters *h264Parameters=[[IRTCVideoCodecParameters alloc] init];
           h264Parameters.name=IRTCVideoCodecH264;
           IRTCVideoEncodingParameters *videoParameters=[[IRTCVideoEncodingParameters alloc]init];
           videoParameters.codec=h264Parameters;
           videoParameters.maxBitrate = 512;
           options.video=[NSArray arrayWithObjects:videoParameters, nil];
           IRTCAudioCodecParameters* pcmuParameters=[[IRTCAudioCodecParameters alloc] init];
           pcmuParameters.name=IRTCAudioCodecPcmu;
           IRTCAudioEncodingParameters *audioParameters=[[IRTCAudioEncodingParameters alloc] init];
           audioParameters.codec=pcmuParameters;
           options.audio=[NSArray arrayWithObjects:audioParameters, nil];
           self.mediaOptions.publishOptions = options;
       }else{
           self.mediaOptions = [mediaOptions copy];
       }
       API *api = [API shared];
       [api loginWithUrl:serviceUrl name:name password:password
                     org:org complete:^(CallBackObject * _Nonnull result) {
           if (result.code == 200) {
               // 登录成功后初始化 ccs 和 irtc
               self.ccsClient = [[CCSClient alloc] init];
               self.irtcSDK = [[IRTCSDK alloc] init];
               self.irtcSDK.delegate = self;
               self.ccsClient.irtcSDK = self.irtcSDK;
               // 处理返回的数据
               self.zcoModelUserInfo = [[ZcoModelUserInfo alloc] initWithDictionary:[result.userInfo valueForKey:@"data"]];
               api.token = self.zcoModelUserInfo.accessToken;
               self.baseUrl = serviceUrl;
               // 登录成功后连接 CCS
               [self.ccsClient connectWithUrl:self.baseUrl andToken:api.token complete:^(CallBackObject * _Nonnull connectResult) {
                   if (connectResult.code == 200) {
                       self.ccsClient.ivcsSDKDelegate = self.delegate;
                       // 设置 ccs 消息的 delegate
                       MyCcsClientMessageDelegate *messageDelegate = [[MyCcsClientMessageDelegate alloc] init];
                       messageDelegate.ivcsCustomerDelegate = self.delegate;
                       self.ccsClient.messageDelegate = messageDelegate;
                       // 保存用户信息
                       self.ccsClient.userInfo = self.zcoModelUserInfo;
                       onSuccess(self.zcoModelUserInfo);
                   }else{
                       onFailure([IvcsCustomer sdkonFailureWithResponse:connectResult]);
                   }
               }];
           }else{
               onFailure([IvcsCustomer sdkonFailureWithResponse:result]);
           }
       }];
}

- (void)requestSession:(NSInteger)serviceId withFormId:(NSInteger) formId onSuccess:(void (^)(ZcoModelSessionInfo * _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    NSString *gender = [@"male" caseInsensitiveCompare:self.zcoModelUserInfo.tokenData.data.profile.gender] == NSOrderedSame ? @"先生" : @"女士";
    NSDictionary *requestParameter = @{
        @"media":@"video",
        @"userData":@{
            @"service":@(serviceId),
            @"specifyAgent":@"",
            @"formId" : @(formId),
            @"gender" : gender,
            @"fullName" : self.zcoModelUserInfo.tokenData.data.profile.fullName,
            @"media" : @"video",
            @"clientInfo":@{
                @"type":@"ios"
            }
        },
        @"clientInfo":@{
            @"type":@"ios"
        }
    };
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient requestSession:requestParameter onSuccess:^(NSDictionary * _Nonnull result) {
            ZcoModelSessionInfo *sessionInfo = [[ZcoModelSessionInfo alloc] initWithDictionary:result];
            self.roomToken = sessionInfo.roomToken;
            onSuccess(sessionInfo);
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}


-(void)quitSession:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    MyLog(@"irtc in ivcs 开始离开房间：%@" , self.irtcSDK);
    [self.irtcSDK leaveRoomSuccess:^{
        MyLog(@"irtc in ivcs 离开房间成功");
    } onFailure:^(NSError * _Nonnull error) {
        MyLog(@"irtc in ivcs 离开房间失败:%@" , error);
    }];
    
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        NSLog(@"IVCSSDK: ivcs quit session success.");
        [self.ccsClient quitSession:@{} onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        NSLog(@"IVCSSDK: ivcs quit session failure.");
        onFailure(error);
    }];
    
}

-(void)startVideoWithLabel:(NSString *)label andRenderView:(IRTCCameraPreviewView *)view onSuccess: (void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
#ifdef DEBUG
    // debug 模式下打印 irtc 日志
    IRTCSetMinDebugLogLevel(IRTCLoggingSeverityVerbose);
#endif
    NSLog(@"startVideo,irtc client,%@",self.irtcSDK);
    MyLog(@"开始加入房间 token：%@" , self.roomToken);
    [self.irtcSDK joinRoomWithToken:self.roomToken onSuccess:^(IRTCConferenceInfo * _Nonnull info) {
        MyLog(@"加入房间成功");
        [self.irtcSDK publishLocalStreamToRoomWithStreamLabel:label mediaStreamSettingOptions:self.mediaOptions onSuccess:^(IRTCLocalCameraStream * _Nonnull localStream, IRTCConferencePublication * _Nonnull publication) {
            self.localStreamLabel = label;
            [localStream attachCameraPreview:view];
            self.localStream = localStream;
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            MyLog(@"pub 本地流失败：%@" , error);
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        MyLog(@"加入房间失败：%@" , error);
        onFailure(error);
    }];
    
}

-(void)renderStreamWithLabel:(NSString *)label renderView:(NSObject<IRTCVideoRenderer>*)renderer onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    IRTCRemoteStream *stream = [self.labelAndStreams valueForKey:label];
    [self.irtcSDK subscribeStreamWithLabel:label IRTCRemoteStream:stream onSuccess:^(IRTCConferenceSubscription * _Nonnull subscription) {
        [stream attach:renderer];
        dispatch_async(dispatch_get_main_queue(), ^{
            onSuccess();
        });
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

- (void)detachStreamWithLabel:(NSString *)label renderView:(NSObject<IRTCVideoRenderer> *)view{
    if (label == nil) {
        return;
    }
    if ([self.localStreamLabel isEqualToString:label]) {
        [self.localStream detach:view];
        return;
    }
    IRTCRemoteStream *stream = [self.labelAndStreams valueForKey:label];
    if(!stream){
        stream = [self.irtcSDK getRemoteStreamByVideoLabel:label];
    }
    [stream detach:view];
    [self.labelAndStreams removeObjectForKey:label];
}

- (void)attachStreamWithLabel:(NSString *)label renderView:(NSObject<IRTCVideoRenderer> *)view{
    if ([self.localStreamLabel isEqualToString:label]) {
        [self.localStream attach:view];
        return;
    }
    IRTCStream *stream = [self.labelAndStreams valueForKey:label];
    if(!stream){
        stream = [self.irtcSDK getRemoteStreamByVideoLabel:label];
    }
    [self.labelAndStreams setObject:stream forKey:label];
    [stream attach:view];
}

- (void)switchCameraOnSuccess:(nullable void (^)(void))onSuccess onFailure:(nullable void (^)(NSError * _Nonnull))onFailure{
    [self.irtcSDK switchCameraOnSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}


-(void)muteWithMediaType:(MediaType)type onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    IRTCTrackKind kind;
    if (type == MediaTypeVideo) {
        kind = IRTCTrackKindVideo;
    }else if(type == MediaTypeAudio){
        kind = IRTCTrackKindAudio;
    }else{
        kind = IRTCTrackKindUnknown;
    }
    [self.irtcSDK muteWithMediaType:kind onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)unmuteWithMediaType:(MediaType)type onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    IRTCTrackKind kind;
    if (type == MediaTypeVideo) {
        kind = IRTCTrackKindVideo;
    }else if(type == MediaTypeAudio){
        kind = IRTCTrackKindAudio;
    }else{
        kind = IRTCTrackKindUnknown;
    }
    [self.irtcSDK unmuteWithMediaType:kind onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)shareResourceWithType:(NSString *)type resourceUrl:(NSString *)url resourceName:(NSString *)name toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient shareResourceWithType:type resourceUrl:url resourceName:name toRoles:roles onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)shareResourceWithType:(NSString *)type uploadUrl:(NSString *)uploadUrl fileData:(NSData *)fileData fileName:(NSString *)fileName mimeType:(NSString *)mimeType toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient shareResourceWithType:type uploadUrl:uploadUrl fileData:fileData fileName:fileName mimeType:mimeType toRoles:roles onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)sendCustomMessage:(id)data toRoles:(NSString *__nullable)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendCustomMessage:data toRoles:checkRole(roles) onSuccess:^{
            if(onSuccess){
                onSuccess();
            }
        } onFailure:^(NSError * _Nonnull error) {
            if (onFailure) {
                onFailure(error);
            }
        }];
    } onFailure:^(NSError * _Nonnull error) {
        if (onFailure) {
            onFailure(error);
        }
    }];
}

-(void)sendFormData:(NSDictionary *)data toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendFormData:data toRoles:checkRole(roles) onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)sendTextMessage:(NSString *)data toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendTextMessage:data toRoles:checkRole(roles) onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)sendMessageConfirmation:(ZcoModelConfirmData *)data toRoles:(NSString * __nullable)roles onSuccess:(void (^ __nullable)(void))onSuccess onFailure:(void (^ __nullable)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendMessageConfirmation:data toRoles:checkRole(roles) onSuccess:^{
            if (onSuccess) {
                onSuccess();
            }
        } onFailure:^(NSError * _Nonnull error) {
            if (onFailure) {
                onFailure(error);
            }
        }];
    } onFailure:^(NSError * _Nonnull error) {
        if (onFailure) {
            onFailure(error);
        }
    }];
}

-(void)sendSnapshotMessage:(NSString *)imageUrl toRoles:(NSString * __nullable)roles onSuccess:(void (^__nullable)(void))onSuccess onFailure:(void (^ __nullable)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        NSDictionary *data = @{
            @"url":imageUrl,
            @"name":@"Signature",
            @"type":@"pic"
        };
        [self.ccsClient sendSnapshotMessage:data toRoles:checkRole(roles) onSuccess:^{
                if (onSuccess) {
                    onSuccess();
                }
            } onFailure:^(NSError * _Nonnull error) {
                if (onFailure) {
                    onFailure(error);
                }
            }];
        } onFailure:^(NSError * _Nonnull error) {
            if(onFailure){
                onFailure(error);
            }
        }];
}

- (void)sendPeerCMD:(ZcoModelCMD *)cmd to:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendPeerCMD:cmd to:checkRole(roles) onSuccess:onSuccess onFailure:onFailure];
        } onFailure:^(NSError * _Nonnull error) {
            if (onFailure) {
                onFailure(error);
            }
        }];
}

- (void)sendPeerCancel:(ZcoModelCMD *)cmd to:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendPeerCancel:cmd to:checkRole(roles) onSuccess:onSuccess onFailure:onFailure];
        } onFailure:^(NSError * _Nonnull error) {
            if (onFailure) {
                onFailure(error);
            }
        }];
}

- (void)sendPeerResponse:(ZcoModelCMD *)cmd to:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendPeerResponse:cmd to:checkRole(roles) onSuccess:onSuccess onFailure:onFailure];
        } onFailure:^(NSError * _Nonnull error) {
            if (onFailure) {
                onFailure(error);
            }
        }];
}

- (void)sendHandWritingMessage:(NSString * _Nullable)msg to:(NSString * _Nullable)roles{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        if (msg == nil) {
            [self.ccsClient sendHandWritingMessage:@"{\"version\":\"3.4.0\",\"objects\":[]}" to:checkRole(roles)];
        }else{
            [self.ccsClient sendHandWritingMessage:msg to:checkRole(roles)];
        }
            
        } onFailure:^(NSError * _Nonnull error) {
            NSLog(@"sendHandWritingMessage failed: %@" , error);
        }];
}

-(void)sureUserInfoWithSessionId:(NSString *)sessionId url:(NSString *)url userInfo:(NSMutableDictionary *)userInfo onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    API *api = [API shared];
    [api uploadUserInfoWithSessionId:sessionId url:url userInfo:userInfo onSuccess:^(NSString * _Nonnull formId) {
        NSString *message = [NSString stringWithFormat:@"formid=%@",formId];
        [self sendTextMessage:message toRoles:@"agents" onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)uploadFormDataWithSessionId:(NSString *)sessionId url:(NSString *)url parameter:(NSMutableDictionary *)parameter onSuccess:(void (^)(id _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    API *api = [API shared];
    [api uploadFormDataWithSessionId:sessionId url:url parameter:parameter onSuccess:^(id _Nonnull response) {
        onSuccess(response);
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

+(NSError *)sdkonFailureWithResponse:(CallBackObject *)result{
    NSError *error = [[NSError alloc] initWithDomain:ivcsSDKErrorDomain code:result.code userInfo:result.userInfo];
    return error;
}

- (void)refreshTicket{
    [self.ccsClient refreshTicket];
}

- (void)getScenarios:(void (^)(NSArray<ZcoModelSessionInfo *> *))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[API shared] getScenarios:self.baseUrl onSuccess:onSuccess onFailure:onFailure];
}

-(void)getSnapShotImage:(void (^)(UIImage*))onSuccess onFailure:(void (^)(NSError*))onFailure{
    [self.irtcSDK getSnapShotImage:^(UIImage * _Nonnull image) {
        onSuccess(image);
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

#pragma mark IRTCSDKDelegate
- (void)onStreamAddWithLabel:(NSString *)label{
    if (self.delegate && [self.delegate respondsToSelector:@selector(onStreamAddWithLabel:)]) {
        [self.delegate onStreamAddWithLabel:label];
    }
}

- (void)onStreamRemoveWithLabel:(NSString *)label{
    if (self.delegate && [self.delegate respondsToSelector:@selector(onStreamRemoveWithLabel:)]) {
        [self.delegate onStreamRemoveWithLabel:label];
       }
}

- (CGSize)getVideoSizeByVideoLable:(NSString *)videoLabel{
    return [self.irtcSDK getVideoSizeByVideoLabel:videoLabel];
}

- (void)releaseAll{
    // 释放 irtc 的占用的资源
    if (self.irtcSDK != nil) {
//        [self.irtcSDK dealloc];
    }
}

- (void)confirmCollect:(NSDictionary *)data onSuccess:(void (^)(CallBackObject *_Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[API shared] confirmCollect:data onSuccess:onSuccess onFailure:onFailure];
}

/// 更新收集信息的表单
-(void)updateCollectForm:(NSInteger) formId onSuccess:(void (^)(id))onSuccess
               onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[API shared] updateCollectForm:@{
        @"formId":@(formId),
        @"sessionId":self.ccsClient.sessionId
    } onSuccess:onSuccess onFailure:onFailure];
}

@end
